Question :

What kind of people survived for example kids,women,men

Acquire Data

As the problem statement itself carring the two set of Data training data,test data Here we will just have a look of what kind of data it is .

library(dplyr)
library(knitr)
library(DT)
train_df<-read.csv("Titanic_DataSet/train.csv",stringsAsFactors=F)
cat(paste('\ntest data structure having rows :\n', nrow(train_df)) )

test data structure having rows :
 891
str(train_df)
'data.frame':   891 obs. of  12 variables:
 $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
 $ Survived   : int  0 1 1 1 0 0 0 0 1 1 ...
 $ Pclass     : int  3 1 3 1 3 3 1 3 3 2 ...
 $ Name       : chr  "Braund, Mr. Owen Harris" "Cumings, Mrs. John Bradley (Florence Briggs Thayer)" "Heikkinen, Miss. Laina" "Futrelle, Mrs. Jacques Heath (Lily May Peel)" ...
 $ Sex        : chr  "male" "female" "female" "female" ...
 $ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
 $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
 $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
 $ Ticket     : chr  "A/5 21171" "PC 17599" "STON/O2. 3101282" "113803" ...
 $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
 $ Cabin      : chr  "" "C85" "" "C123" ...
 $ Embarked   : chr  "S" "C" "S" "S" ...
test_df<-read.csv("Titanic_DataSet/test.csv",stringsAsFactors=F)
cat(paste('\ntest data structure having rows :\n', nrow(test_df)) )

test data structure having rows :
 418
str(test_df)
'data.frame':   418 obs. of  11 variables:
 $ PassengerId: int  892 893 894 895 896 897 898 899 900 901 ...
 $ Pclass     : int  3 3 2 3 3 3 3 2 3 3 ...
 $ Name       : chr  "Kelly, Mr. James" "Wilkes, Mrs. James (Ellen Needs)" "Myles, Mr. Thomas Francis" "Wirz, Mr. Albert" ...
 $ Sex        : chr  "male" "female" "male" "male" ...
 $ Age        : num  34.5 47 62 27 22 14 30 26 18 21 ...
 $ SibSp      : int  0 1 0 0 1 0 0 1 0 2 ...
 $ Parch      : int  0 0 0 0 1 0 0 1 0 0 ...
 $ Ticket     : chr  "330911" "363272" "240276" "315154" ...
 $ Fare       : num  7.83 7 9.69 8.66 12.29 ...
 $ Cabin      : chr  "" "" "" "" ...
 $ Embarked   : chr  "Q" "S" "Q" "S" ...
datatable(train_df,options=list(pageLength=5))

cat('\n test_df ----\n')

 test_df ----
datatable(test_df,options=list(pageLength=5))

Insights:

  1. As from the above result we can see that training Data structure is having one field extra that is “survived” as comapred to testing data which we have to predict in this data

  2. PasseengerId:Unique Id Assigned to each traveller

  3. Pclass : 1 for First Class 2 for Second Class 3 for third class

  4. Name : Name is with first name and Last name Mostly starting from the Mr.Miss And Mrs. Few caseswith Master and don etc .

  5. Age : Age of Passenger, few values are missing here

  6. SibSp : Number of sibling or spouse 0 for none

  7. Parch : Number of parents/childern travelling 0 for none

  8. Ticket : Ticket Number

  9. Fare : how much each traveller paid for the travel

  10. Cabin : Cabin number allocated

  11. Embarked: Port of emabarkation C,S,Q

Explore

Now we will start exploring the data

First we will do Univariate analysis,which means finding the continous and categorical variable Continous Variable are : Passenger Id, PClass, Age,Sibsp,Parch,Ticekt Number ,Fare Categorical : Sex, Embarked Character value Variable : Name ,Cabin,Ticekt

Get here the summary of relavant data like,pclass,age,sibsp,parch,fare to see the average

library(ggplot2)
library(plotly)
library(grid)
library(gridExtra)
cat('\nSummary Of Pclass\n')

Summary Of Pclass
par(mfrow=c(1,2))
#Summary for Pclass
ggplotly (ggplot(train_df, aes(x="",y = Pclass)) +
    geom_boxplot(colour = "red", fill = "skyblue")+ggtitle("Pclass Summary"))

#Summary for Age 
ggplotly (ggplot(train_df, aes(x="",y = Age)) +
    geom_boxplot(colour = "red", fill = "skyblue")+ggtitle("Age Summary"))
Removed 177 rows containing non-finite values (stat_boxplot).

#Summary for SibSp
ggplotly (ggplot(train_df, aes(x="",y = SibSp)) +
    geom_boxplot(colour = "red", fill = "skyblue")+ggtitle("SibSp Summary"))

#Summary for Parch
ggplotly (ggplot(train_df, aes(x="",y = Parch)) +
    geom_boxplot(colour = "red", fill = "skyblue")+ggtitle("Parch Summary"))

#Summary for Fare
ggplotly (ggplot(train_df, aes(x="",y = Fare)) +
    geom_boxplot(colour = "red", fill = "skyblue")+ggtitle("Fare Summary"))

Insight:

From the Results few things can be identified

  1. Average age of traveller is around 29-30 and maximum age is 80

  2. very few people were traveling with siblings and maximum number of siblings/spouse is 8

  3. Maximum number of parents/childern is 6 and more outl

  4. Average Fare is around 14.45 but outliers are more so prediction from fare will be tough

let see,from the given if we can find the Fare of first class, second class and third class Not sure it is required or not.

fare_single_passenger<-subset(train_df,(train_df$SibSp == 0) & (train_df$Parch ==0),select=c(Pclass,Fare))
fare_single_passenger
fare_single_passenger<-aggregate(fare_single_passenger[, 2], list(fare_single_passenger$Pclass), mean)
           
cat(paste('\n\nAverage Fare of First Class ',fare_single_passenger[1,2]))


Average Fare of First Class  63.6725137614679
cat(paste('\n\nAverage Fare of Second Class ',fare_single_passenger[2,2]))


Average Fare of Second Class  14.0661057692308
cat(paste('\n\nAverage Fare of Third Class ',fare_single_passenger[3,2]))


Average Fare of Third Class  9.27205185185185

Change the variable into numeric to fit on continous scale

train_df$Sex<-as.numeric(as.factor(train_df$Sex))
train_df$Embarked<-as.numeric(as.factor(train_df$Embarked))
test_df$Sex<-as.numeric(as.factor(test_df$Sex))
test_df$Embarked<-as.numeric(as.factor(test_df$Embarked))

further will visualize the data between survival and other variates .

here i am using the bar plot and manipulate so that user can choose the column value,number of row and see the respective bar plot

library(ggplot2)#library loadedr
library(ggthemes)
library(manipulate)
############# manipulate for the size and aes value
manipulate(
    ggplot(data=train_df[sample(1:nrow(train_df),samplesize),], aes_string(x = x_axis, y = "Survived",fill=x_axis,size=samplesize)) +
        geom_bar(stat="identity",width=0.5)+
        scale_fill_gradient(low="blue", high="red")+
        theme_solarized() ,
    samplesize=slider(100,nrow(train_df)),
    x_axis=picker("Pclass","Age","Sex","SibSp","Parch","Embarked")
    
)

###################

Insights:

1.From the above few points number female who survived is more as compared to male

  1. Can’t predict much from the bar plot as there is no significant relationship seen

Check the survival of group/family travelling together and singleton here i will use the ticket Number as if people are sharing the same ticket Number ,more chances that they are family or group travelling together .

library(DT)
lenofUniqueTicekt<-length(unique(train_df$Ticket))
cat(paste('Number of uniques Ticket',lenofUniqueTicekt))
Number of uniques Ticket 681
FamGp_df<-train_df[duplicated(train_df[,"Ticket"])|duplicated(train_df[,"Ticket"],fromLast  = TRUE),] %>%
          arrange(Ticket) %>%group_by(Ticket) %>% summarise(groupFmSize=n(),Survived=sum(Survived))
datatable(FamGp_df, options = list(pageLength = 5))

From the above table looks like possiblity of survival is little better if travelling with group/Family

before going into more visulaization just wanted to check which variable is playing a significant role in predicticing the survival applying logistics regression as the dependent variable is in binary form (0,1 ) means survived or not . Removing few columns like name passengerID ticket,cabin as name and passenger ID is unique and cabin is having lots of missing data .Ticket is again character value not worth .

training_model <- glm(Survived ~.-(Name+PassengerId +Ticket+Cabin),family=binomial(link='logit'),data=train_df,maxit=50)
summary(training_model)

Call:
glm(formula = Survived ~ . - (Name + PassengerId + Ticket + Cabin), 
    family = binomial(link = "logit"), data = train_df, maxit = 50)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.7278  -0.6439  -0.3824   0.6243   2.4564  

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  8.598284   0.849163  10.126  < 2e-16 ***
Pclass      -1.222334   0.163604  -7.471 7.94e-14 ***
Sex         -2.620535   0.219879 -11.918  < 2e-16 ***
Age         -0.043306   0.008196  -5.284 1.27e-07 ***
SibSp       -0.360270   0.127584  -2.824  0.00475 ** 
Parch       -0.057472   0.123335  -0.466  0.64123    
Fare         0.001469   0.002527   0.581  0.56107    
Embarked    -0.180037   0.131888  -1.365  0.17223    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 964.52  on 713  degrees of freedom
Residual deviance: 633.95  on 706  degrees of freedom
  (177 observations deleted due to missingness)
AIC: 649.95

Number of Fisher Scoring iterations: 5

From the above result we can see the following

1.SibSp, Fare and Embarked are not statistically significant. 2.Sex has lowest p-Value indicating strong association between the gender and survival rate

Hence taking few Few more visualization related to Pclass,Sex,Age using plotly

library(ggplot2)
library(plotly)
#Draw thw chart for Male and female survivela
p<-ggplot(train_df, aes(Age, fill = factor(Survived))) + 
  geom_histogram() + 
  facet_grid(.~Sex)+theme_dark()
ggplotly(p)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Removed 177 rows containing non-finite values (stat_bin).
library(crosstalk)
shared_train_df <- SharedData$new(train_df)
bscols(d3scatter(shared_train_df,~SibSp,~Age,~Sex,width="100%",height = 300),d3scatter(shared_train_df,~Parch,~Age,~Sex,width = "100%",height = 300)
    )

Insights

Clearly from the graph that female of age between 12-42 survived and very few male survived between the same age group so prediction make better add few more column like child ,FemaleAdult ,maleAdult category as they have Female adult high possiblity of survival.

Here on adding both the data(training and test ), as need to filled the missing values in both .

#combine both the data 

library(dplyr)

titanic_df<-bind_rows(train_df,test_df)

#check the totral number of rows just to verify 
cat(paste('\ncomplete  data structure having rows :', nrow(titanic_df)) )
#checking the structure as well
str(titanic_df)

Add the Family size to each person

library(dplyr)
library(DT)

nrow((titanic_df))


#again recreate the Family/Group Size with whole data as we are going to add the family size in the test data to make prediction better 
FamGp_df<-titanic_df[duplicated(titanic_df[,"Ticket"])|duplicated(titanic_df[,"Ticket"],fromLast  = TRUE),] %>%
          arrange(Ticket) %>%group_by(Ticket) %>% summarise(groupFmSize=n(),Survived=sum(Survived))


#keep only two column Ticket ,groupFmSize  
FamGp_df <-FamGp_df[,c("Ticket","groupFmSize")]  

#display the data



datatable(FamGp_df, options = list(pageLength = 5))

From the above we have got family/group size which we will merge the groupFmSize to get the size in the whole


library(dplyr)

titanic_df<-merge(x=titanic_df,y=FamGp_df,by="Ticket",all=TRUE)

#just to cross verify check the number of rows

cat(paste('\ncomplete  data structure having rows :', nrow(titanic_df)) )



#reorder the column value

col_order<-c("PassengerId","Survived","Pclass","Name","Sex","Age","SibSp","Parch","Ticket","groupFmSize","Fare","Cabin","Embarked")

titanic_df<-titanic_df[,col_order] %>% arrange(PassengerId)





datatable(titanic_df, options = list(pageLength = 5))

Replacing all the NA values in groupFamSize with 0

titanic_df$groupFmSize[is.na(titanic_df$groupFmSize)]<-0

datatable(titanic_df, options = list(pageLength = 5))

Insights:

From the above we got complete data Now let us analyze which all value are missing

No missing value in data passenserId,Name,Sex,SibSp,Parch ,Ticket,Pclass Few Missing value in Age , Cabin and two missing value in Embarked and one missing value in fare

here i am ignoring few of attributes which is not much useful as we saw earlier like embarked,cabin(having more missing value) and fare as well

check the how many data is missing using the mice plot



 library(VIM)
library(plotly)


 mice_plot <- aggr(titanic_df[,c("Age")], col=c('blue','red'),
                    numbers=TRUE, sortVars=TRUE,
                    labels=c("Age")
                   , cex.axis=.7,
                    gap=3, ylab=c("Missing data","Pattern"))
 

Install Package install.packages(“Hmisc”)

filling the missing value in Age with the impute method taking the meadin of the data

library(Hmisc)
titanic_df$Age <- with(titanic_df, impute(Age, median))
#titanic_df[,c("Age")]

now all the missing value in age has been filled

As we discussed earlier, now Adding column AgeCategory will add if <18 child female Adult if age >18 and sex is female and male Adult if age>18 and sex is male


titanic_df$AgeCategory[titanic_df$Age <= 18] <-'child'
titanic_df$AgeCategory[titanic_df$Age > 18.00 & titanic_df$Sex =='female']<- 'FemaleAdult'
titanic_df$AgeCategory[titanic_df$Age > 18.00 & titanic_df$Sex =='male']<- 'maleAdult'
titanic_df$AgeCategory<-factor(titanic_df$AgeCategory)

#just to verify the data 
datatable(titanic_df, options = list(pageLength = 5))

Now all the required data has been filled and resturtured so splitting again the data into training and test data

final_train_df<-titanic_df[1:nrow(train_df),]
final_test_df<-titanic_df[nrow(train_df)+1:nrow(test_df),]

datatable(final_train_df, options = list(pageLength = 5))

datatable(final_test_df, options = list(pageLength = 5))

Predict

predicting the model on training data here i am using decision tree to model as we have seen only few variable are significant so considering only with Pclass,Age,Sex,AgeCategory,FamgpSize

library("rpart")
library("rpart.plot")
rtree_fit <- rpart(Survived ~ Pclass+Age+factor(AgeCategory)+Sex+groupFmSize, 
          final_train_df,method="class") 
summary(rtree_fit)
rpart.plot(rtree_fit,extra=104, box.palette="GnBu",
branch.lty=3, shadow.col="gray", nn=TRUE)

Insights

from the first level of tree shows out of total traveller only 38% survived while 62 % died and further only 19 % of male survievd however this ratio was more in case of women

prediction

 library(MASS) 


survivalPrediction <- predict(rtree_fit,final_test_df,type="class")
str(survivalPrediction)

tableP<-table(survivalPrediction)
pct <- round(tableP/sum(tableP) * 100)
label<-c("0","1")
lbls <- paste(label,'-',pct,'%')  # add percents to labels 
 pie(tableP,col=c("red","yellow"),labels = lbls)  
 
 #save the data in CSV file 
predicted_df <- data.frame(PassengerID = final_test_df$PassengerId, Survived = survivalPrediction)
head(predicted_df,200)


write.csv(predicted_df, file = 'Titanic_Prediction_Rpart.csv', row.names = F)

conclusion

From the final data pie chart 65% people has been died while 35% has survived from disaster.

This is my first Exploration .Any improvments and suggestions always welcome:

LS0tDQp0aXRsZTogIlRpdGFuaWMgRGF0YXNldCBFeHBsb3JhdGlvbiINCmF1dGhvcjogIlNhbmdlZXRhIg0KZGF0ZTogIjE2IGp1bHkgMjAxNyINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCiNRdWVzdGlvbiA6ICANCldoYXQga2luZCBvZiBwZW9wbGUgc3Vydml2ZWQgZm9yIGV4YW1wbGUga2lkcyx3b21lbixtZW4gDQoNCg0KI0FjcXVpcmUgRGF0YSANCg0KQXMgdGhlIHByb2JsZW0gc3RhdGVtZW50IGl0c2VsZiBjYXJyaW5nIHRoZSB0d28gc2V0IG9mIERhdGEgdHJhaW5pbmcgZGF0YSx0ZXN0IGRhdGENCkhlcmUgd2Ugd2lsbCBqdXN0IGhhdmUgYSBsb29rIG9mIHdoYXQga2luZCBvZiBkYXRhIGl0IGlzIC4NCg0KDQpgYGB7cn0gDQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShEVCkNCg0KDQp0cmFpbl9kZjwtcmVhZC5jc3YoIlRpdGFuaWNfRGF0YVNldC90cmFpbi5jc3YiLHN0cmluZ3NBc0ZhY3RvcnM9RikNCmNhdChwYXN0ZSgnXG50ZXN0IGRhdGEgc3RydWN0dXJlIGhhdmluZyByb3dzIDpcbicsIG5yb3codHJhaW5fZGYpKSApDQpzdHIodHJhaW5fZGYpDQoNCg0KdGVzdF9kZjwtcmVhZC5jc3YoIlRpdGFuaWNfRGF0YVNldC90ZXN0LmNzdiIsc3RyaW5nc0FzRmFjdG9ycz1GKQ0KY2F0KHBhc3RlKCdcbnRlc3QgZGF0YSBzdHJ1Y3R1cmUgaGF2aW5nIHJvd3MgOlxuJywgbnJvdyh0ZXN0X2RmKSkgKQ0Kc3RyKHRlc3RfZGYpDQoNCg0KDQoNCmRhdGF0YWJsZSh0cmFpbl9kZixvcHRpb25zPWxpc3QocGFnZUxlbmd0aD01KSkNCg0KDQpjYXQoJ1xuIHRlc3RfZGYgLS0tLVxuJykNCg0KDQpkYXRhdGFibGUodGVzdF9kZixvcHRpb25zPWxpc3QocGFnZUxlbmd0aD01KSkNCg0KDQoNCmBgYA0KSW5zaWdodHM6DQoNCjEuIEFzIGZyb20gdGhlIGFib3ZlIHJlc3VsdCB3ZSBjYW4gc2VlIHRoYXQgdHJhaW5pbmcgRGF0YSBzdHJ1Y3R1cmUgaXMgaGF2aW5nICBvbmUgZmllbGQgZXh0cmEgdGhhdCBpcyAic3Vydml2ZWQiIGFzIGNvbWFwcmVkIHRvICAgICAgIHRlc3RpbmcgZGF0YSB3aGljaCB3ZSBoYXZlIHRvIHByZWRpY3QgaW4gdGhpcyBkYXRhIA0KDQoyLiBQYXNzZWVuZ2VySWQ6VW5pcXVlIElkIEFzc2lnbmVkIHRvIGVhY2ggdHJhdmVsbGVyDQoNCjMuIFBjbGFzcyA6IDEgZm9yIEZpcnN0IENsYXNzDQogICAgICAgICAgICAyIGZvciBTZWNvbmQgQ2xhc3MNCiAgICAgICAgICAgIDMgZm9yIHRoaXJkIGNsYXNzDQogICAgICAgICAgICANCjQuICBOYW1lIDogTmFtZSBpcyB3aXRoIGZpcnN0IG5hbWUgYW5kIExhc3QgbmFtZSBNb3N0bHkgc3RhcnRpbmcgZnJvbSB0aGUgTXIuTWlzcyBBbmQgTXJzLiBGZXcgY2FzZXN3aXRoIE1hc3RlciBhbmQgZG9uIGV0YyAuDQoNCjUuICBBZ2UgOiAgQWdlIG9mIFBhc3NlbmdlciwgZmV3IHZhbHVlcyBhcmUgbWlzc2luZyBoZXJlDQoNCjYuICBTaWJTcCA6IE51bWJlciBvZiBzaWJsaW5nIG9yIHNwb3VzZSAwIGZvciBub25lIA0KDQo3LiAgUGFyY2ggOiBOdW1iZXIgb2YgcGFyZW50cy9jaGlsZGVybiB0cmF2ZWxsaW5nICAwIGZvciBub25lIA0KDQo4LiAgVGlja2V0IDogVGlja2V0IE51bWJlciANCg0KOS4gIEZhcmUgOiBob3cgbXVjaCBlYWNoIHRyYXZlbGxlciBwYWlkIGZvciB0aGUgdHJhdmVsDQoNCjEwLiBDYWJpbiA6IENhYmluIG51bWJlciBhbGxvY2F0ZWQNCg0KMTEuIEVtYmFya2VkOiBQb3J0IG9mIGVtYWJhcmthdGlvbiBDLFMsUSANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgIA0KI0V4cGxvcmUNCg0KTm93IHdlIHdpbGwgc3RhcnQgZXhwbG9yaW5nIHRoZSBkYXRhIA0KDQpGaXJzdCB3ZSB3aWxsIGRvIFVuaXZhcmlhdGUgYW5hbHlzaXMsd2hpY2ggbWVhbnMgZmluZGluZyB0aGUgY29udGlub3VzIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZQ0KQ29udGlub3VzIFZhcmlhYmxlIGFyZSA6IFBhc3NlbmdlciBJZCwgUENsYXNzLCBBZ2UsU2lic3AsUGFyY2gsVGljZWt0IE51bWJlciAsRmFyZQ0KQ2F0ZWdvcmljYWwgOiBTZXgsIEVtYmFya2VkIA0KQ2hhcmFjdGVyIHZhbHVlIFZhcmlhYmxlIDogTmFtZSAsQ2FiaW4sVGljZWt0IA0KDQoNCkdldCBoZXJlIHRoZSBzdW1tYXJ5IG9mIHJlbGF2YW50IGRhdGEgbGlrZSxwY2xhc3MsYWdlLHNpYnNwLHBhcmNoLGZhcmUgdG8gc2VlIHRoZSBhdmVyYWdlICANCg0KYGBge3J9DQoNCg0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZ3JpZCkNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KDQpjYXQoJ1xuU3VtbWFyeSBPZiBQY2xhc3NcbicpDQoNCnBhcihtZnJvdz1jKDEsMikpDQoNCiNTdW1tYXJ5IGZvciBQY2xhc3MNCmdncGxvdGx5IChnZ3Bsb3QodHJhaW5fZGYsIGFlcyh4PSIiLHkgPSBQY2xhc3MpKSArDQogICAgZ2VvbV9ib3hwbG90KGNvbG91ciA9ICJyZWQiLCBmaWxsID0gInNreWJsdWUiKStnZ3RpdGxlKCJQY2xhc3MgU3VtbWFyeSIpKQ0KDQojU3VtbWFyeSBmb3IgQWdlIA0KZ2dwbG90bHkgKGdncGxvdCh0cmFpbl9kZiwgYWVzKHg9IiIseSA9IEFnZSkpICsNCiAgICBnZW9tX2JveHBsb3QoY29sb3VyID0gInJlZCIsIGZpbGwgPSAic2t5Ymx1ZSIpK2dndGl0bGUoIkFnZSBTdW1tYXJ5IikpDQoNCiNTdW1tYXJ5IGZvciBTaWJTcA0KDQpnZ3Bsb3RseSAoZ2dwbG90KHRyYWluX2RmLCBhZXMoeD0iIix5ID0gU2liU3ApKSArDQogICAgZ2VvbV9ib3hwbG90KGNvbG91ciA9ICJyZWQiLCBmaWxsID0gInNreWJsdWUiKStnZ3RpdGxlKCJTaWJTcCBTdW1tYXJ5IikpDQoNCg0KI1N1bW1hcnkgZm9yIFBhcmNoDQpnZ3Bsb3RseSAoZ2dwbG90KHRyYWluX2RmLCBhZXMoeD0iIix5ID0gUGFyY2gpKSArDQogICAgZ2VvbV9ib3hwbG90KGNvbG91ciA9ICJyZWQiLCBmaWxsID0gInNreWJsdWUiKStnZ3RpdGxlKCJQYXJjaCBTdW1tYXJ5IikpDQoNCiNTdW1tYXJ5IGZvciBGYXJlDQoNCmdncGxvdGx5IChnZ3Bsb3QodHJhaW5fZGYsIGFlcyh4PSIiLHkgPSBGYXJlKSkgKw0KICAgIGdlb21fYm94cGxvdChjb2xvdXIgPSAicmVkIiwgZmlsbCA9ICJza3libHVlIikrZ2d0aXRsZSgiRmFyZSBTdW1tYXJ5IikpDQoNCg0KDQpgYGANCkluc2lnaHQ6DQoNCkZyb20gdGhlIFJlc3VsdHMgZmV3IHRoaW5ncyBjYW4gYmUgaWRlbnRpZmllZCANCg0KMS4gQXZlcmFnZSBhZ2Ugb2YgdHJhdmVsbGVyIGlzIGFyb3VuZCAyOS0zMCBhbmQgbWF4aW11bSBhZ2UgaXMgODANCg0KMi4gdmVyeSBmZXcgcGVvcGxlIHdlcmUgdHJhdmVsaW5nIHdpdGggc2libGluZ3MgYW5kIG1heGltdW0gbnVtYmVyIG9mIHNpYmxpbmdzL3Nwb3VzZSBpcyA4DQoNCjMuICBNYXhpbXVtIG51bWJlciBvZiBwYXJlbnRzL2NoaWxkZXJuIGlzIDYgYW5kIG1vcmUgb3V0bA0KDQo0LiBBdmVyYWdlIEZhcmUgaXMgYXJvdW5kIDE0LjQ1IGJ1dCBvdXRsaWVycyBhcmUgbW9yZSBzbyBwcmVkaWN0aW9uIGZyb20gZmFyZSB3aWxsIGJlIHRvdWdoDQoNCg0KbGV0IHNlZSxmcm9tIHRoZSBnaXZlbiBpZiB3ZSBjYW4gZmluZCB0aGUgRmFyZSBvZiBmaXJzdCBjbGFzcywgc2Vjb25kIGNsYXNzIGFuZCB0aGlyZCBjbGFzcw0KTm90IHN1cmUgaXQgaXMgcmVxdWlyZWQgb3Igbm90Lg0KDQpgYGB7cn0NCg0KDQpmYXJlX3NpbmdsZV9wYXNzZW5nZXI8LXN1YnNldCh0cmFpbl9kZiwodHJhaW5fZGYkU2liU3AgPT0gMCkgJiAodHJhaW5fZGYkUGFyY2ggPT0wKSxzZWxlY3Q9YyhQY2xhc3MsRmFyZSkpDQoNCmZhcmVfc2luZ2xlX3Bhc3Nlbmdlcg0KDQpkYXRhdGFibGUoZmFyZV9zaW5nbGVfcGFzc2VuZ2VyLG9wdGlvbnM9bGlzdChwYWdlTGVuZ3RoPTUpKQ0KDQpmYXJlX3NpbmdsZV9wYXNzZW5nZXI8LWFnZ3JlZ2F0ZShmYXJlX3NpbmdsZV9wYXNzZW5nZXJbLCAyXSwgbGlzdChmYXJlX3NpbmdsZV9wYXNzZW5nZXIkUGNsYXNzKSwgbWVhbikNCg0KICAgICAgICAgICANCmNhdChwYXN0ZSgnXG5cbkF2ZXJhZ2UgRmFyZSBvZiBGaXJzdCBDbGFzcyAnLGZhcmVfc2luZ2xlX3Bhc3NlbmdlclsxLDJdKSkNCmNhdChwYXN0ZSgnXG5cbkF2ZXJhZ2UgRmFyZSBvZiBTZWNvbmQgQ2xhc3MgJyxmYXJlX3NpbmdsZV9wYXNzZW5nZXJbMiwyXSkpDQpjYXQocGFzdGUoJ1xuXG5BdmVyYWdlIEZhcmUgb2YgVGhpcmQgQ2xhc3MgJyxmYXJlX3NpbmdsZV9wYXNzZW5nZXJbMywyXSkpDQoNCg0KDQoNCg0KYGBgDQoNCkNoYW5nZSB0aGUgdmFyaWFibGUgaW50byBudW1lcmljICB0byBmaXQgb24gY29udGlub3VzIHNjYWxlIA0KDQpgYGB7cn0NCg0KdHJhaW5fZGYkU2V4PC1hcy5udW1lcmljKGFzLmZhY3Rvcih0cmFpbl9kZiRTZXgpKQ0KdHJhaW5fZGYkRW1iYXJrZWQ8LWFzLm51bWVyaWMoYXMuZmFjdG9yKHRyYWluX2RmJEVtYmFya2VkKSkNCg0KdGVzdF9kZiRTZXg8LWFzLm51bWVyaWMoYXMuZmFjdG9yKHRlc3RfZGYkU2V4KSkNCnRlc3RfZGYkRW1iYXJrZWQ8LWFzLm51bWVyaWMoYXMuZmFjdG9yKHRlc3RfZGYkRW1iYXJrZWQpKQ0KDQoNCmBgYA0KZnVydGhlciB3aWxsIHZpc3VhbGl6ZSB0aGUgZGF0YSBiZXR3ZWVuIHN1cnZpdmFsIGFuZCBvdGhlciB2YXJpYXRlcyAuDQoNCmhlcmUgaSBhbSB1c2luZyB0aGUgYmFyIHBsb3QgYW5kIG1hbmlwdWxhdGUgc28gdGhhdCB1c2VyIGNhbiBjaG9vc2UgdGhlIGNvbHVtbiB2YWx1ZSxudW1iZXIgb2Ygcm93ICBhbmQgc2VlIHRoZSByZXNwZWN0aXZlIGJhciBwbG90DQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KGdncGxvdDIpI2xpYnJhcnkgbG9hZGVkcg0KbGlicmFyeShnZ3RoZW1lcykNCg0KbGlicmFyeShtYW5pcHVsYXRlKQ0KDQoNCg0KDQojIyMjIyMjIyMjIyMjIG1hbmlwdWxhdGUgZm9yIHRoZSBzaXplIGFuZCBhZXMgdmFsdWUNCg0KDQptYW5pcHVsYXRlKA0KICAgIGdncGxvdChkYXRhPXRyYWluX2RmW3NhbXBsZSgxOm5yb3codHJhaW5fZGYpLHNhbXBsZXNpemUpLF0sIGFlc19zdHJpbmcoeCA9IHhfYXhpcywgeSA9ICJTdXJ2aXZlZCIsZmlsbD14X2F4aXMsc2l6ZT1zYW1wbGVzaXplKSkgKw0KICAgICAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsd2lkdGg9MC41KSsNCiAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImJsdWUiLCBoaWdoPSJyZWQiKSsNCiAgICAgICAgdGhlbWVfc29sYXJpemVkKCkgLA0KICAgIHNhbXBsZXNpemU9c2xpZGVyKDEwMCxucm93KHRyYWluX2RmKSksDQogICAgeF9heGlzPXBpY2tlcigiUGNsYXNzIiwiQWdlIiwiU2V4IiwiU2liU3AiLCJQYXJjaCIsIkVtYmFya2VkIikNCiAgICANCikNCiMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KDQoNCmBgYA0KSW5zaWdodHM6DQoNCjEuRnJvbSB0aGUgYWJvdmUgZmV3IHBvaW50cyBudW1iZXIgZmVtYWxlIHdobyBzdXJ2aXZlZCBpcyBtb3JlIGFzIGNvbXBhcmVkIHRvIG1hbGUgDQoNCjIuIENhbid0IHByZWRpY3QgbXVjaCBmcm9tIHRoZSBiYXIgcGxvdCBhcyB0aGVyZSBpcyBubyBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgc2Vlbg0KDQoNCg0KQ2hlY2sgdGhlIHN1cnZpdmFsIG9mIGdyb3VwL2ZhbWlseSAgdHJhdmVsbGluZyB0b2dldGhlciBhbmQgc2luZ2xldG9uIGhlcmUgaSB3aWxsIHVzZSB0aGUgdGlja2V0IE51bWJlciBhcyBpZiBwZW9wbGUgYXJlIHNoYXJpbmcgdGhlIHNhbWUgdGlja2V0IE51bWJlciAsbW9yZSBjaGFuY2VzIHRoYXQgdGhleSBhcmUgZmFtaWx5IG9yIGdyb3VwIHRyYXZlbGxpbmcgdG9nZXRoZXIgLg0KDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KERUKQ0KDQpsZW5vZlVuaXF1ZVRpY2VrdDwtbGVuZ3RoKHVuaXF1ZSh0cmFpbl9kZiRUaWNrZXQpKQ0KDQpjYXQocGFzdGUoJ051bWJlciBvZiB1bmlxdWVzIFRpY2tldCcsbGVub2ZVbmlxdWVUaWNla3QpKQ0KDQoNCkZhbUdwX2RmPC10cmFpbl9kZltkdXBsaWNhdGVkKHRyYWluX2RmWywiVGlja2V0Il0pfGR1cGxpY2F0ZWQodHJhaW5fZGZbLCJUaWNrZXQiXSxmcm9tTGFzdCAgPSBUUlVFKSxdICU+JQ0KICAgICAgICAgIGFycmFuZ2UoVGlja2V0KSAlPiVncm91cF9ieShUaWNrZXQpICU+JSBzdW1tYXJpc2UoZ3JvdXBGbVNpemU9bigpLFN1cnZpdmVkPXN1bShTdXJ2aXZlZCkpDQoNCg0KDQoNCmRhdGF0YWJsZShGYW1HcF9kZiwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDUpKQ0KDQoNCg0KYGBgDQpGcm9tIHRoZSBhYm92ZSB0YWJsZSBsb29rcyBsaWtlIHBvc3NpYmxpdHkgb2Ygc3Vydml2YWwgaXMgbGl0dGxlIGJldHRlciAgaWYgdHJhdmVsbGluZyB3aXRoIGdyb3VwL0ZhbWlseSANCg0KYmVmb3JlIGdvaW5nIGludG8gbW9yZSB2aXN1bGFpemF0aW9uIGp1c3Qgd2FudGVkIHRvIGNoZWNrIHdoaWNoIHZhcmlhYmxlIGlzIHBsYXlpbmcgYSBzaWduaWZpY2FudCByb2xlIGluIHByZWRpY3RpY2luZyB0aGUgc3Vydml2YWwgYXBwbHlpbmcgbG9naXN0aWNzIHJlZ3Jlc3Npb24gYXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpcyBpbiBiaW5hcnkgZm9ybSAoMCwxICkgbWVhbnMgc3Vydml2ZWQgb3Igbm90IC4NClJlbW92aW5nIGZldyBjb2x1bW5zIGxpa2UgbmFtZSBwYXNzZW5nZXJJRCB0aWNrZXQsY2FiaW4gYXMgbmFtZSBhbmQgcGFzc2VuZ2VyIElEIGlzIHVuaXF1ZSBhbmQgY2FiaW4gaXMgaGF2aW5nIGxvdHMgb2YgbWlzc2luZyBkYXRhIC5UaWNrZXQgaXMgYWdhaW4gY2hhcmFjdGVyIHZhbHVlIG5vdCB3b3J0aCAuDQoNCmBgYHtyfQ0KDQp0cmFpbmluZ19tb2RlbCA8LSBnbG0oU3Vydml2ZWQgfi4tKE5hbWUrUGFzc2VuZ2VySWQgK1RpY2tldCtDYWJpbiksZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT10cmFpbl9kZixtYXhpdD01MCkNCnN1bW1hcnkodHJhaW5pbmdfbW9kZWwpDQoNCmBgYA0KRnJvbSB0aGUgYWJvdmUgcmVzdWx0IHdlIGNhbiBzZWUgdGhlIGZvbGxvd2luZw0KDQoxLlNpYlNwLCBGYXJlIGFuZCBFbWJhcmtlZCBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuDQoyLlNleCBoYXMgbG93ZXN0IHAtVmFsdWUgaW5kaWNhdGluZyBzdHJvbmcgYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgZ2VuZGVyIGFuZCBzdXJ2aXZhbCByYXRlIA0KDQoNCkhlbmNlIHRha2luZyBmZXcgRmV3IG1vcmUgdmlzdWFsaXphdGlvbiByZWxhdGVkIHRvIFBjbGFzcyxTZXgsQWdlIHVzaW5nIHBsb3RseSANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCiNEcmF3IHRodyBjaGFydCBmb3IgTWFsZSBhbmQgZmVtYWxlIHN1cnZpdmVsYQ0KDQpwPC1nZ3Bsb3QodHJhaW5fZGYsIGFlcyhBZ2UsIGZpbGwgPSBmYWN0b3IoU3Vydml2ZWQpKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICBmYWNldF9ncmlkKC5+U2V4KSt0aGVtZV9kYXJrKCkNCg0KZ2dwbG90bHkocCkNCg0KYGBgDQpgYGB7cn0NCg0KbGlicmFyeShjcm9zc3RhbGspDQoNCnNoYXJlZF90cmFpbl9kZiA8LSBTaGFyZWREYXRhJG5ldyh0cmFpbl9kZikNCg0KYnNjb2xzKGQzc2NhdHRlcihzaGFyZWRfdHJhaW5fZGYsflNpYlNwLH5BZ2UsflNleCx3aWR0aD0iMTAwJSIsaGVpZ2h0ID0gMzAwKSxkM3NjYXR0ZXIoc2hhcmVkX3RyYWluX2RmLH5QYXJjaCx+QWdlLH5TZXgsd2lkdGggPSAiMTAwJSIsaGVpZ2h0ID0gMzAwKQ0KICAgICkNCg0KDQpgYGANCkluc2lnaHRzDQoNCkNsZWFybHkgZnJvbSB0aGUgZ3JhcGggdGhhdCBmZW1hbGUgb2YgYWdlIGJldHdlZW4gMTItNDIgc3Vydml2ZWQgYW5kIHZlcnkgZmV3IG1hbGUgc3Vydml2ZWQgYmV0d2VlbiB0aGUgc2FtZSBhZ2UgZ3JvdXAgDQpzbyBwcmVkaWN0aW9uIG1ha2UgYmV0dGVyIGFkZCBmZXcgbW9yZSBjb2x1bW4gbGlrZSBjaGlsZCAsRmVtYWxlQWR1bHQgLG1hbGVBZHVsdCBjYXRlZ29yeSBhcyB0aGV5IGhhdmUgRmVtYWxlICBhZHVsdCBoaWdoIHBvc3NpYmxpdHkgb2Ygc3Vydml2YWwuDQoNCg0KDQpIZXJlIG9uIGFkZGluZyAgYm90aCB0aGUgZGF0YSh0cmFpbmluZyBhbmQgdGVzdCApLCBhcyBuZWVkIHRvIGZpbGxlZCB0aGUgbWlzc2luZyB2YWx1ZXMgaW4gYm90aCAgLg0KDQpgYGB7cn0NCiNjb21iaW5lIGJvdGggdGhlIGRhdGEgDQoNCmxpYnJhcnkoZHBseXIpDQoNCnRpdGFuaWNfZGY8LWJpbmRfcm93cyh0cmFpbl9kZix0ZXN0X2RmKQ0KDQojY2hlY2sgdGhlIHRvdHJhbCBudW1iZXIgb2Ygcm93cyBqdXN0IHRvIHZlcmlmeSANCmNhdChwYXN0ZSgnXG5jb21wbGV0ZSAgZGF0YSBzdHJ1Y3R1cmUgaGF2aW5nIHJvd3MgOicsIG5yb3codGl0YW5pY19kZikpICkNCiNjaGVja2luZyB0aGUgc3RydWN0dXJlIGFzIHdlbGwNCnN0cih0aXRhbmljX2RmKQ0KDQoNCg0KDQpgYGANCg0KQWRkIHRoZSBGYW1pbHkgc2l6ZSB0byBlYWNoIHBlcnNvbiANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShEVCkNCg0KbnJvdygodGl0YW5pY19kZikpDQoNCg0KI2FnYWluIHJlY3JlYXRlIHRoZSBGYW1pbHkvR3JvdXAgU2l6ZSB3aXRoIHdob2xlIGRhdGEgYXMgd2UgYXJlIGdvaW5nIHRvIGFkZCB0aGUgZmFtaWx5IHNpemUgaW4gdGhlIHRlc3QgZGF0YSB0byBtYWtlIHByZWRpY3Rpb24gYmV0dGVyIA0KRmFtR3BfZGY8LXRpdGFuaWNfZGZbZHVwbGljYXRlZCh0aXRhbmljX2RmWywiVGlja2V0Il0pfGR1cGxpY2F0ZWQodGl0YW5pY19kZlssIlRpY2tldCJdLGZyb21MYXN0ICA9IFRSVUUpLF0gJT4lDQogICAgICAgICAgYXJyYW5nZShUaWNrZXQpICU+JWdyb3VwX2J5KFRpY2tldCkgJT4lIHN1bW1hcmlzZShncm91cEZtU2l6ZT1uKCksU3Vydml2ZWQ9c3VtKFN1cnZpdmVkKSkNCg0KDQoja2VlcCBvbmx5IHR3byBjb2x1bW4gVGlja2V0ICxncm91cEZtU2l6ZSAgDQpGYW1HcF9kZiA8LUZhbUdwX2RmWyxjKCJUaWNrZXQiLCJncm91cEZtU2l6ZSIpXSAgDQoNCiNkaXNwbGF5IHRoZSBkYXRhDQoNCg0KDQpkYXRhdGFibGUoRmFtR3BfZGYsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCg0KDQoNCmBgYA0KRnJvbSB0aGUgYWJvdmUgd2UgaGF2ZSBnb3QgZmFtaWx5L2dyb3VwIHNpemUgDQp3aGljaCB3ZSB3aWxsIG1lcmdlIHRoZSBncm91cEZtU2l6ZSB0byBnZXQgdGhlIHNpemUgaW4gdGhlIHdob2xlDQoNCg0KYGBge3J9DQoNCmxpYnJhcnkoZHBseXIpDQoNCnRpdGFuaWNfZGY8LW1lcmdlKHg9dGl0YW5pY19kZix5PUZhbUdwX2RmLGJ5PSJUaWNrZXQiLGFsbD1UUlVFKQ0KDQojanVzdCB0byBjcm9zcyB2ZXJpZnkgY2hlY2sgdGhlIG51bWJlciBvZiByb3dzDQoNCmNhdChwYXN0ZSgnXG5jb21wbGV0ZSAgZGF0YSBzdHJ1Y3R1cmUgaGF2aW5nIHJvd3MgOicsIG5yb3codGl0YW5pY19kZikpICkNCg0KDQoNCiNyZW9yZGVyIHRoZSBjb2x1bW4gdmFsdWUNCg0KY29sX29yZGVyPC1jKCJQYXNzZW5nZXJJZCIsIlN1cnZpdmVkIiwiUGNsYXNzIiwiTmFtZSIsIlNleCIsIkFnZSIsIlNpYlNwIiwiUGFyY2giLCJUaWNrZXQiLCJncm91cEZtU2l6ZSIsIkZhcmUiLCJDYWJpbiIsIkVtYmFya2VkIikNCg0KdGl0YW5pY19kZjwtdGl0YW5pY19kZlssY29sX29yZGVyXSAlPiUgYXJyYW5nZShQYXNzZW5nZXJJZCkNCg0KDQoNCg0KDQpkYXRhdGFibGUodGl0YW5pY19kZiwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDUpKQ0KDQoNCg0KYGBgDQpSZXBsYWNpbmcgYWxsIHRoZSBOQSB2YWx1ZXMgaW4gZ3JvdXBGYW1TaXplICB3aXRoIDAgDQoNCmBgYHtyfQ0KdGl0YW5pY19kZiRncm91cEZtU2l6ZVtpcy5uYSh0aXRhbmljX2RmJGdyb3VwRm1TaXplKV08LTANCg0KZGF0YXRhYmxlKHRpdGFuaWNfZGYsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCmBgYA0KDQpJbnNpZ2h0czoNCg0KRnJvbSB0aGUgYWJvdmUgd2UgZ290IGNvbXBsZXRlIGRhdGEgTm93IGxldCB1cyBhbmFseXplIHdoaWNoIGFsbCB2YWx1ZSBhcmUgbWlzc2luZyANCg0KTm8gbWlzc2luZyB2YWx1ZSBpbiAgZGF0YSBwYXNzZW5zZXJJZCxOYW1lLFNleCxTaWJTcCxQYXJjaCAsVGlja2V0LFBjbGFzcw0KRmV3IE1pc3NpbmcgdmFsdWUgaW4gQWdlICwgQ2FiaW4gYW5kIHR3byBtaXNzaW5nIHZhbHVlIGluIEVtYmFya2VkIGFuZCBvbmUgbWlzc2luZyB2YWx1ZSBpbiBmYXJlDQoNCg0KaGVyZSBpIGFtIGlnbm9yaW5nIGZldyBvZiBhdHRyaWJ1dGVzIHdoaWNoIGlzIG5vdCBtdWNoIHVzZWZ1bCBhcyB3ZSBzYXcgZWFybGllciBsaWtlIGVtYmFya2VkLGNhYmluKGhhdmluZyBtb3JlIG1pc3NpbmcgdmFsdWUpIGFuZCBmYXJlIGFzIHdlbGwgDQoNCg0KY2hlY2sgdGhlIGhvdyBtYW55IGRhdGEgaXMgbWlzc2luZyAgdXNpbmcgdGhlIG1pY2UgcGxvdA0KYGBge3J9DQoNCg0KIGxpYnJhcnkoVklNKQ0KbGlicmFyeShwbG90bHkpDQoNCg0KIG1pY2VfcGxvdCA8LSBhZ2dyKHRpdGFuaWNfZGZbLGMoIkFnZSIpXSwgY29sPWMoJ2JsdWUnLCdyZWQnKSwNCiAgICAgICAgICAgICAgICAgICAgbnVtYmVycz1UUlVFLCBzb3J0VmFycz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiQWdlIikNCiAgICAgICAgICAgICAgICAgICAsIGNleC5heGlzPS43LA0KICAgICAgICAgICAgICAgICAgICBnYXA9MywgeWxhYj1jKCJNaXNzaW5nIGRhdGEiLCJQYXR0ZXJuIikpDQogDQpgYGANCkluc3RhbGwgUGFja2FnZSBpbnN0YWxsLnBhY2thZ2VzKCJIbWlzYyIpDQoNCmZpbGxpbmcgIHRoZSBtaXNzaW5nIHZhbHVlIGluIEFnZSB3aXRoIHRoZSBpbXB1dGUgbWV0aG9kIHRha2luZyB0aGUgbWVhZGluIG9mIHRoZSBkYXRhDQoNCmBgYHtyfQ0KbGlicmFyeShIbWlzYykNCnRpdGFuaWNfZGYkQWdlIDwtIHdpdGgodGl0YW5pY19kZiwgaW1wdXRlKEFnZSwgbWVkaWFuKSkNCiN0aXRhbmljX2RmWyxjKCJBZ2UiKV0NCg0KYGBgDQpub3cgYWxsIHRoZSBtaXNzaW5nIHZhbHVlIGluIGFnZSBoYXMgYmVlbiBmaWxsZWQgDQoNCkFzIHdlIGRpc2N1c3NlZCBlYXJsaWVyLCBub3cgQWRkaW5nIGNvbHVtbiBBZ2VDYXRlZ29yeSB3aWxsIGFkZCBpZiA8MTggY2hpbGQgZmVtYWxlIEFkdWx0IGlmIGFnZSA+MTggYW5kIHNleCBpcyBmZW1hbGUgYW5kIG1hbGUgQWR1bHQgaWYgYWdlPjE4IGFuZCBzZXggaXMgbWFsZSANCg0KDQpgYGB7cn0NCg0KdGl0YW5pY19kZiRBZ2VDYXRlZ29yeVt0aXRhbmljX2RmJEFnZSA8PSAxOF0gPC0nY2hpbGQnDQp0aXRhbmljX2RmJEFnZUNhdGVnb3J5W3RpdGFuaWNfZGYkQWdlID4gMTguMDAgJiB0aXRhbmljX2RmJFNleCA9PSdmZW1hbGUnXTwtICdGZW1hbGVBZHVsdCcNCnRpdGFuaWNfZGYkQWdlQ2F0ZWdvcnlbdGl0YW5pY19kZiRBZ2UgPiAxOC4wMCAmIHRpdGFuaWNfZGYkU2V4ID09J21hbGUnXTwtICdtYWxlQWR1bHQnDQp0aXRhbmljX2RmJEFnZUNhdGVnb3J5PC1mYWN0b3IodGl0YW5pY19kZiRBZ2VDYXRlZ29yeSkNCg0KI2p1c3QgdG8gdmVyaWZ5IHRoZSBkYXRhIA0KZGF0YXRhYmxlKHRpdGFuaWNfZGYsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCg0KDQoNCmBgYA0KDQpOb3cgYWxsIHRoZSByZXF1aXJlZCBkYXRhIGhhcyBiZWVuIGZpbGxlZCBhbmQgcmVzdHVydHVyZWQgc28gc3BsaXR0aW5nIGFnYWluIHRoZSBkYXRhIGludG8gdHJhaW5pbmcgYW5kIHRlc3QgZGF0YSANCg0KYGBge3J9DQpmaW5hbF90cmFpbl9kZjwtdGl0YW5pY19kZlsxOm5yb3codHJhaW5fZGYpLF0NCmZpbmFsX3Rlc3RfZGY8LXRpdGFuaWNfZGZbbnJvdyh0cmFpbl9kZikrMTpucm93KHRlc3RfZGYpLF0NCg0KZGF0YXRhYmxlKGZpbmFsX3RyYWluX2RmLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkpDQoNCmRhdGF0YWJsZShmaW5hbF90ZXN0X2RmLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkpDQoNCg0KDQpgYGANCg0KI1ByZWRpY3QgDQpwcmVkaWN0aW5nIHRoZSBtb2RlbCBvbiB0cmFpbmluZyBkYXRhIA0KaGVyZSBpIGFtIHVzaW5nIGRlY2lzaW9uIHRyZWUgdG8gbW9kZWwgDQphcyB3ZSBoYXZlIHNlZW4gb25seSBmZXcgdmFyaWFibGUgYXJlIHNpZ25pZmljYW50IHNvIGNvbnNpZGVyaW5nIG9ubHkgd2l0aCBQY2xhc3MsQWdlLFNleCxBZ2VDYXRlZ29yeSxGYW1ncFNpemUNCg0KYGBge3J9DQpsaWJyYXJ5KCJycGFydCIpDQpsaWJyYXJ5KCJycGFydC5wbG90IikNCnJ0cmVlX2ZpdCA8LSBycGFydChTdXJ2aXZlZCB+IFBjbGFzcytBZ2UrZmFjdG9yKEFnZUNhdGVnb3J5KStTZXgrZ3JvdXBGbVNpemUsIA0KICAgICAgICAgIGZpbmFsX3RyYWluX2RmLG1ldGhvZD0iY2xhc3MiKSANCnN1bW1hcnkocnRyZWVfZml0KQ0KcnBhcnQucGxvdChydHJlZV9maXQsZXh0cmE9MTA0LCBib3gucGFsZXR0ZT0iR25CdSIsDQpicmFuY2gubHR5PTMsIHNoYWRvdy5jb2w9ImdyYXkiLCBubj1UUlVFKQ0KYGBgDQpJbnNpZ2h0cw0KDQpmcm9tIHRoZSBmaXJzdCBsZXZlbCBvZiB0cmVlIHNob3dzIG91dCBvZiB0b3RhbCB0cmF2ZWxsZXIgb25seSAzOCUgc3Vydml2ZWQgd2hpbGUgNjIgJSBkaWVkDQphbmQgZnVydGhlciBvbmx5IDE5ICUgb2YgbWFsZSBzdXJ2aWV2ZCBob3dldmVyIHRoaXMgcmF0aW8gd2FzIG1vcmUgaW4gY2FzZSBvZiB3b21lbiANCg0KI3ByZWRpY3Rpb24NCmBgYHtyfQ0KIGxpYnJhcnkoTUFTUykgDQoNCg0Kc3Vydml2YWxQcmVkaWN0aW9uIDwtIHByZWRpY3QocnRyZWVfZml0LGZpbmFsX3Rlc3RfZGYsdHlwZT0iY2xhc3MiKQ0Kc3RyKHN1cnZpdmFsUHJlZGljdGlvbikNCg0KdGFibGVQPC10YWJsZShzdXJ2aXZhbFByZWRpY3Rpb24pDQpwY3QgPC0gcm91bmQodGFibGVQL3N1bSh0YWJsZVApICogMTAwKQ0KbGFiZWw8LWMoIjAiLCIxIikNCmxibHMgPC0gcGFzdGUobGFiZWwsJy0nLHBjdCwnJScpICAjIGFkZCBwZXJjZW50cyB0byBsYWJlbHMgDQogcGllKHRhYmxlUCxjb2w9YygicmVkIiwieWVsbG93IiksbGFiZWxzID0gbGJscykgIA0KIA0KICNzYXZlIHRoZSBkYXRhIGluIENTViBmaWxlIA0KcHJlZGljdGVkX2RmIDwtIGRhdGEuZnJhbWUoUGFzc2VuZ2VySUQgPSBmaW5hbF90ZXN0X2RmJFBhc3NlbmdlcklkLCBTdXJ2aXZlZCA9IHN1cnZpdmFsUHJlZGljdGlvbikNCmhlYWQocHJlZGljdGVkX2RmLDIwMCkNCg0KDQp3cml0ZS5jc3YocHJlZGljdGVkX2RmLCBmaWxlID0gJ1RpdGFuaWNfUHJlZGljdGlvbl9ScGFydC5jc3YnLCByb3cubmFtZXMgPSBGKQ0KDQoNCg0KDQpgYGANCg0KI2NvbmNsdXNpb24NCg0KRnJvbSB0aGUgZmluYWwgZGF0YSBwaWUgY2hhcnQgNjUlIHBlb3BsZSBoYXMgYmVlbiBkaWVkIHdoaWxlIDM1JSBoYXMgc3Vydml2ZWQgZnJvbSBkaXNhc3Rlci4NCg0KDQpUaGlzIGlzIG15IGZpcnN0IEV4cGxvcmF0aW9uIC5BbnkgaW1wcm92bWVudHMgYW5kICBzdWdnZXN0aW9ucyBhbHdheXMgd2VsY29tZToNCg0KDQoNCg==